/*
 *  c15/a/lib/kernel/bitmap.c
 *
 *  操作系统真相还原 - 郑刚
 */

#include <Lucnx/debug.h>
#include <Lucnx/bitmap.h>
#include <Lucnx/types.h>
#include <Lucnx/debug.h>
#include <Lucnx/string.h>

#define BITMAP_MASK 1

void bitmap_init(bitmap_t* p_btm) 
{
   memset(p_btm->bits, 0, p_btm->btmp_len);   
}

bool bitmap_scan_test(bitmap_t* p_btm, u32 bit_idx) 
{
   u32 byte_idx = bit_idx / 8;
   if (byte_idx > p_btm->btmp_len)
   {
        panic("error bitmap idx: %d", bit_idx);
   }
   
   u32 bit_odd  = bit_idx % 8;
   return (p_btm->bits[byte_idx] & (BITMAP_MASK << bit_odd));
}

int bitmap_scan(bitmap_t* p_btm, u32 cnt) 
{
   u32 idx_byte = 0;	 

   while (( 0xff == p_btm->bits[idx_byte]) && (idx_byte < p_btm->btmp_len)) 
   {
      idx_byte++;
   }

   assert(idx_byte < p_btm->btmp_len);

   if (idx_byte == p_btm->btmp_len) 
   {  
      return -1;
   }

   int idx_bit = 0;

   while ((u8)(BITMAP_MASK << idx_bit) & p_btm->bits[idx_byte]) 
   { 
	 idx_bit++;
   }
	 
   int bit_idx_start = idx_byte * 8 + idx_bit;
   if (cnt == 1)
   {
      // DEBUGK("idx:%d", bit_idx_start);
      return bit_idx_start;
   }

   u32 bit_left = (p_btm->btmp_len * 8 - bit_idx_start);   
   u32 next_bit = bit_idx_start + 1;
   u32 count = 1;	      

   bit_idx_start = -1;
   while (bit_left-- > 0) 
   {
      if (!(bitmap_scan_test(p_btm, next_bit))) 
      { 
         count++;
      } 
      else 
      {
         count = 0;
      }
      if (count == cnt) 
      {	    
	 bit_idx_start = next_bit - cnt + 1;
	 break;
      }
      next_bit++;          
   }
   return bit_idx_start;
}

int bitmap_set(bitmap_t* p_btm, u32 bit_idx, int8 value) 
{
   assert((value == 0) || (value == 1));
   int8 byte_idx = bit_idx / 8;    
   u32 bit_odd  = bit_idx % 8;    

   if (bit_idx >= p_btm->btmp_len * 8)
   {
      return EOF;
   }

   if (value) 
   {
      p_btm->bits[byte_idx] |= (BITMAP_MASK << bit_odd);
   }
   else
   {
      p_btm->bits[byte_idx] &= ~(BITMAP_MASK << bit_odd);
   }
}